module Graphics.IGraphics;

public enum BlendMode{
	ALPHA_DISABLE = 0, // αブレンドしない
	ALPHA_NORMAL  = 1, // 半透明
	ALPHA_ADD     = 2, // 加算
} //

public interface IGraphics{
	const int ALPHA_DISABLE = 0; // αブレンドしない
	const int ALPHA_NORMAL  = 1; // 半透明
	const int ALPHA_ADD     = 2; // 加算
	int screenWidth();
	int screenHeight();

	/**
	* 画面に見える領域の左上,右下座標を指定する。
	* OpenGLのViewportとは違うので注意。
	*/
	void setViewport( float x1, float y1 , float x2 , float y2  );
	Rectangle viewrect();
	void viewrect( Rectangle rect );

	int blendMode();
	void blendMode( int mode );
	
	Color backgroundColor();
	void backgroundColor( Color c);
	
	void clear();
	void drawRect(   float x , float y , float width  , float height , Color color , float rotate = 0 , float lineWidth = 1);
	void drawFilledRect(   float x , float y , float width  , float height , Color color , float rotate = 0 );
	void drawLine( float x1 , float y1 , float x2 , float y2 ,Color color  , float lineWidth = 1);
	void drawImage( ITexture tx , float x , float y , float width , float height , float rotate = 0);
	void drawImage( ITexture tx , float x , float y , float width , float height , Color color , float rotate = 0);
//	void drawImage( ITexture tx , float centerX , float centerY , float width , float height);
	void drawText(string text , int x, int y, Color color , float fontWidth = 32 , float fontHeight = 48 );

	ISprite getSprite();
	bool addDrawingEntry( IDrawingEntry o );
	bool draw();

	/**
	 @share = 他のITextureとビットマップデータ部のメモリを共有するかどうかを指定。
	  デフォルトでは、keyとfileNameが同一なら同じメモリを共有する。
	  中身を加工したりする場合は他にも影響が出ないようにfalseにする。
	*/
	ITexture createTexture( string key , string fileName                       , bool share = true );
	ITexture createTexture( string key , string fileName , Color keyColor      , bool share = true );
	ITexture createTexture( string key , string fileName , int keyX , int keyY , bool share = true );

	bool dispose();
} //


public interface IDrawingEntry{
	float x();
	float y();
	float z();

	bool draw( IGraphics g );
	bool drawingEntry( IGraphics g );
	
} //


public interface ISprite : IDrawingEntry{
	void x( float xx );
	void y( float yy );
	void z( float zz );
	float x();
	float y();
	float z();
	float width();
	void width(float w);
	float height();
	void height(float h);
	float opacity();
	void opacity(float o);
	float rotate();
	void rotate(float r);

	bool busy();
	ITexture texture();
	void texture( ITexture tx  );

	bool flipV();
	void flipV( bool f );
	bool flipH();
	void flipH( bool f );
	
	bool visible();
	void visible( bool f );

	void reset();
	void release();
	void call();
	void moveTo( float xx , float yy );
	void moveBy( float xx , float yy );
	void setSize( float ww , float hh );
	
	Color maskColor();
	void maskColor(Color mask);
	void maskColor(int mask);
} //

public class DummySprite :  ISprite {
	public float x(){return 0;}
	public void  x(float x){}
	public float y(){return 0;}
	public void  y(float y){}
	public float z(){return 0;}
	public void  z(float z){}

	public bool draw( IGraphics g ){return true;}
	public bool drawingEntry( IGraphics g ){return true;}

	public this(){}
	public float width(){return 1;}
	public void width(float w){}
	public float height(){return 1;}
	public void height(float h){}
	public float opacity(){return 1;}
	public void opacity(float o){}
	public float rotate(){return 0;}
	public void rotate(float r){}

	public bool busy(){return false;}
	public ITexture texture(){return null;}
	public void texture( ITexture tx  ){}

	public bool flipV(){return false;}
	public void flipV( bool f ){}
	public bool flipH(){return false;}
	public void flipH( bool f ){}
	
	public bool visible(){return false;}
	public void visible( bool f ){}

	public void reset(){}
	public void release(){}
	public void call(){}
	public void moveTo( float xx , float yy ){}
	public void moveBy( float xx , float yy ){}
	public void setSize( float ww , float hh ){}

	public Color maskColor(){return Color.create(0xffffffff);}
	public void maskColor(Color mask){}
	public void maskColor(int mask){}
} //

/*
public class SpritePool {
	private ISprite delegate() _create;
	private ISprite[] _sprites;
	private int _sptr;
	public this( ISprite delegate() c  , int len = 4096){
		_create = c;
		_sprites = new ISprite[ len ];
		_sptr = 0;
	}
	public ISprite get(){
		ISprite ret;
		int len = _sprites.length;
		for( int i = 0 ; i < len ; i ++ ) {
			_sptr = ( _sptr + 1 ) % len;
			if ( _sprites[_sptr] is null ) {
				ret = _create();
				ret.call();
				_sprites[_sptr] = ret;
				break;
			} else 
			if ( !_sprites[_sptr].busy ) {
				ret = _sprites[_sptr];
				ret.call();
				break;
			}
		}
		return ret;
	}
} //
//*/

//*
public class SpritePool(T) {
	private T[] _sprites;
	private int _sptr;
	public this( int len = 4096 ){
		_sprites = new T[ len ];
		_sptr = 0;
	}
	public T get(){
		T ret;
		int len = _sprites.length;
		for( int i = 0 ; i < len ; i ++ ) {
			_sptr = ( _sptr + 1 ) % len;
			if ( _sprites[_sptr] is null ) {
				ret = new T();
				ret.call();
				_sprites[_sptr] = ret;
				break;
			} else 
			if ( !_sprites[_sptr].busy ) {
				ret = _sprites[_sptr];
				ret.call();
				break;
			}
		}
		return ret;
	}
} //
//*/


public interface ITexture{
	uint id();
	int width();
	int height();
	void setFrameSize( int w , int h  , int frameIndex = 0 );
	void setFrameSize( Rectangle rect , int frameIndex = 0 );
	string key();

	void setFrameSizeDiv( int divX , int divY  , int frameIndex = 0 );

	int  frameIndex();
	void frameIndex( int f );
	void setFrameIndex( int x , int y );
//	void opacity( float o );
//	int opacity( );

	Rectangle clipRectangle();

//	Color maskColor();

//	ITexture getClone();

} //







public union Color{
	private uint _color; // CPU依存
	version ( X86 ) {
		private struct{ubyte _b;ubyte _g;ubyte _r;ubyte _a;}
	} else 
	version ( PPC ) {
		private struct{ubyte _a;ubyte _r;ubyte _g;ubyte _b;}
	} else {
		private struct{ubyte _a;ubyte _r;ubyte _g;ubyte _b;}
	}
//	public ubyte* ptr(){return &_b;	} //

	public static Color create( uint c = 0 ) {
		Color ret;
			ret.color = c;
		return ret;
	} //

	public static Color create( int r ,  int g ,  int b ,  int a = 255 ) {
		Color ret;
			ret.r = cast(uint)r;
			ret.g = cast(uint)g;
			ret.b = cast(uint)b;
			ret.a = cast(uint)a;
		return ret;
	} //
	public static Color create( uint r , uint g , uint b , uint a = 255 ) {
		Color ret;
			ret.r = r;
			ret.g = g;
			ret.b = b;
			ret.a = a;
		return ret;
	} //

	public void color ( int c ) {
		_color = cast(uint)c;
	} //

	public uint color(){
		return _color;
	} //
	public void color( uint c ){
		_color = c;
	} //

	public Color clone(){
		Color ret;
			ret.color = _color;
		return ret;
	} //

	public uint r(){return _r;} //
	public void r(uint c){_r = cast(ubyte)c;}

	public uint g(){return _g;} //
	public void g(uint c){_g = cast(ubyte)c;}

	public uint b(){return _b;} //
	public void b(uint c){_b = cast(ubyte)c;}

	public uint a(){return _a;} //
	public void a(uint c){_a = cast(ubyte)c;}

	void opAdd( Color c ) {
		int rr = r + c.r;if ( rr > 255 ) rr = 255;
		int gg = g + c.g;if ( gg > 255 ) gg = 255;
		int bb = b + c.b;if ( bb > 255 ) bb = 255;
		r = rr;
		g = gg;
		b = bb;
	} // 
	void opSub( Color c ) {
		int rr = r - c.r;if ( rr < 0 ) rr = 0;
		int gg = g - c.g;if ( gg < 0 ) gg = 0;
		int bb = b - c.b;if ( bb < 0 ) bb = 0;
		r = rr;
		g = gg;
		b = bb;
	} // 
} //

/*
public final struct Color{
	private uint col;
	private union {
		uint _color;
		struct{
			ubyte _a;
			ubyte _g;
			ubyte _b;
			ubyte _r;
		}
	}

	uint opCast(){ return col;}

	public static Color create( uint c = 0 ) {
		Color ret;
			ret.color = c;
		return ret;
	} //

	public static Color create( int r ,  int g ,  int b ,  int a = 255 ) {
		Color ret;
			ret.r = cast(uint)r;
			ret.g = cast(uint)g;
			ret.b = cast(uint)b;
			ret.a = cast(uint)a;
		return ret;
	} //
	public static Color create( uint r , uint g , uint b , uint a = 255 ) {
		Color ret;
			ret.r = r;
			ret.g = g;
			ret.b = b;
			ret.a = a;
		return ret;
	} //

	public void color( int c ){
		col = cast(uint)c;
	} //

	public uint color(){
		return col;
	} //
	public void color( uint c ){
		col = c;
	} //


	public uint r(){
		return (col >> 16) & 0x000000ffu;
	} //
	public void r(uint c){
		col &= 0xff00ffffu;
		col |= ( c & 0xffu ) << 16; 
	}
	public int g(){
		return (col >>  8) & 0x000000ffu;
	} //
	public void g(uint g){
		col &= 0xffff00ffu;
		col |= ( g & 0xffu ) << 8; 
	} //
	public uint b(){
		return  col        & 0x000000ffu;
	} //
	public void b(uint c){
		col &= 0xffffff00u;
		col |=   c & 0xffu ;
	} //

	public uint a(){
		return (col >> 24) & 0x000000ffu;
	} //
	public void a(uint c){
		col &= 0x00ffffffu;
		col |= (c & 0xffu ) << 24;
	} //
	
	public Color clone(){
		Color ret;
			ret.color = _color;
		return ret;
	} //

} //

*/
public final class Rectangle{
	private float _x,_y,_width,_height;
	public this(){
		this( 0 , 0 , 1 , 1 );
	}
	public this( float width , float height){
		this( 0 , 0 , width , height );
	}
	public this( float x , float y , float width , float height){
		_x = x;
		_y = y;
		_width  = width;
		_height = height;
	}
	public float x(){
		return _x;
	} //
	public void x(float xx){
		_x = xx;
	} //
	public float y(){
		return _y;
	} //
	public void y(float yy){
		_y = yy;
	} //
	public float width(){
		return _width;
	} //
	public void width(float w){
		_width = w;
	} //
	public float height(){
		return _height;
	} //
	public void height(float h){
		_height = h;
	} //

	public float x2(){
		return _x + _width;
	} //
	public void x2(float xx){
		_width = xx - x;
	} //
	public float y2(){
		return _y + _height;
	} //
	public void y2(float yy){
		_height = yy - y;
	} //


	
	public Rectangle clone(){
		return new Rectangle( _x , _y , _width, _height );
	} //
} //